home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / mkid2 / part05 < prev    next >
Encoding:
Internet Message Format  |  1991-10-09  |  38.2 KB

  1. Subject:  v24i093:  Program identifier database tools, Part05/07
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: d7239bcc 65a3e35c b7e56c4a 04c06e6c
  5.  
  6. Submitted-by: Tom Horsley <tom@hcx2.ssd.csd.harris.com>
  7. Posting-number: Volume 24, Issue 93
  8. Archive-name: mkid2/part05
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 5 (of 7)."
  17. # Contents:  iidfun.c mkid.c
  18. # Wrapped by tom@hcx2 on Tue Feb 26 10:03:05 1991
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'iidfun.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'iidfun.c'\"
  22. else
  23. echo shar: Extracting \"'iidfun.c'\" \(17113 characters\)
  24. sed "s/^X//" >'iidfun.c' <<'END_OF_FILE'
  25. X/* iidfun.c - This file holds the utility functions called from iid.y
  26. X */
  27. X
  28. X#include "iiddef.h"
  29. X#ifdef USE_ALLOCA
  30. X
  31. X/* Apparently Sun's need the following to work correctly */
  32. X#ifdef sun
  33. X#include <alloca.h>
  34. X#endif /* sun */
  35. X
  36. X/* Define TEMP_ALLOC to call alloca, and TEMP_FREE to do nothing */
  37. X
  38. X#define TEMP_ALLOC(s) alloca(s)
  39. X#define TEMP_FREE(s)
  40. X
  41. X#else
  42. X
  43. X/* Not using alloca() (not everyone has it) - define TEMP_ALLOC to call
  44. X * malloc() and TEMP_FREE to call free().
  45. X */
  46. X#define TEMP_ALLOC(s) malloc(s)
  47. X#define TEMP_FREE(s)  free(s)
  48. X
  49. X#endif /* USE_ALLOCA */
  50. X
  51. X/* ArgListSize - count the size of an arg list so can alloca() enough
  52. X * space for the command.
  53. X */
  54. Xint
  55. XArgListSize(idlp)
  56. X   id_list_type * idlp ;
  57. X{
  58. X   id_type *      idep ;
  59. X   int            size = 0;
  60. X   
  61. X   idep = idlp->id_list ;
  62. X   while (idep != NULL) {
  63. X      size += 1 + strlen(idep->id);
  64. X      idep = idep->next_id;
  65. X   }
  66. X   return size;
  67. X}
  68. X
  69. X/* SetListSize - count the size of a string build up from a set so we can
  70. X * alloca() enough space for args.
  71. X */
  72. Xint
  73. XSetListSize(sp)
  74. X   set_type * sp ;
  75. X{
  76. X   int            i ;
  77. X   int            size = 0 ;
  78. X   
  79. X   for (i = 0; i < NextFileNum; ++i) {
  80. X      if (FileList[i]->mask_word < sp->set_size) {
  81. X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  82. X            size += 1 + strlen(FileList[i]->name);
  83. X         }
  84. X      }
  85. X   }
  86. X   return size;
  87. X}
  88. X
  89. X/* FlushFiles - clear out the TheFiles array for the start of a new
  90. X * query.
  91. X */
  92. Xvoid
  93. XFlushFiles()
  94. X{
  95. X   int             i ;
  96. X   
  97. X   if (TheFiles != NULL) {
  98. X      for (i = 0; i <= MaxCurFile; ++i) {
  99. X         TheFiles[i] = 0 ;
  100. X      }
  101. X   }
  102. X   MaxCurFile = 0 ;
  103. X}
  104. X
  105. X/* fatal - sometimes the only thing to do is die...
  106. X */
  107. Xvoid
  108. Xfatal(s)
  109. X{
  110. X   fprintf(stderr,"Fatal error: %s\n",s) ;
  111. X   exit(1) ;
  112. X}
  113. X
  114. X/* CountBits - count the number of bits in a bit set. Actually fairly
  115. X * tricky since it needs to deal with sets having infinite tails
  116. X * as a result of a NOT operation.
  117. X */
  118. Xint
  119. XCountBits(sp)
  120. X   set_type * sp ;
  121. X{
  122. X   unsigned long      bit_mask ;
  123. X   int                count = 0 ;
  124. X   int                i ;
  125. X   
  126. X   i = 0;
  127. X   for ( ; ; ) {
  128. X      for (bit_mask = high_bit; bit_mask != 0; bit_mask >>= 1) {
  129. X         if (bit_mask == NextMaskBit && i == NextMaskWord) {
  130. X            return(count) ;
  131. X         }
  132. X         if (i < sp->set_size) {
  133. X            if (sp->set_data[i] & bit_mask) {
  134. X               ++count ;
  135. X            }
  136. X         } else {
  137. X            if (sp->set_tail == 0) return count;
  138. X            if (sp->set_tail & bit_mask) {
  139. X               ++count;
  140. X            }
  141. X         }
  142. X      }
  143. X      ++i;
  144. X   }
  145. X}
  146. X
  147. X/* OneDescription - Print a description of a set. This includes
  148. X * the set number, the number of files in the set, and the
  149. X * set description string.
  150. X */
  151. Xvoid
  152. XOneDescription(sp)
  153. X   set_type * sp ;
  154. X{
  155. X   int        elt_count ;
  156. X   char       setnum[20] ;
  157. X   
  158. X   sprintf(setnum,"S%d",sp->set_num) ;
  159. X   elt_count = CountBits(sp) ;
  160. X   printf("%5s %6d  %s\n",setnum,elt_count,sp->set_desc) ;
  161. X}
  162. X
  163. X/* DescribeSets - Print description of all the sets.
  164. X */
  165. Xvoid
  166. XDescribeSets()
  167. X{
  168. X   int            i ;
  169. X
  170. X   if (NextSetNum > 0) {
  171. X      for (i = 0; i < NextSetNum; ++i) {
  172. X         OneDescription(TheSets[i]) ;
  173. X      }
  174. X   } else {
  175. X      printf("No sets defined yet.\n") ;
  176. X   }
  177. X}
  178. X
  179. X/* SetList - Go through the bit set and add the file names in
  180. X * it to an identifier list.
  181. X */
  182. Xid_list_type *
  183. XSetList(idlp, sp)
  184. X   id_list_type *  idlp ;
  185. X   set_type *      sp ;
  186. X{
  187. X   int        i ;
  188. X   id_type *  idep ;
  189. X   
  190. X   for (i = 0; i < NextFileNum; ++i) {
  191. X      if (FileList[i]->mask_word < sp->set_size) {
  192. X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  193. X            idep = (id_type *)malloc(sizeof(id_type) +
  194. X                                     strlen(FileList[i]->name)) ;
  195. X            if (idep == NULL) {
  196. X               fatal("Out of memory in SetList") ;
  197. X            }
  198. X            idep->next_id = NULL ;
  199. X            strcpy(idep->id, FileList[i]->name) ;
  200. X            idlp = ExtendList(idlp, idep) ;
  201. X         }
  202. X      }
  203. X   }
  204. X   return(idlp) ;
  205. X}
  206. X
  207. X/* PrintSet - Go through the bit set and print the file names
  208. X * corresponding to all the set bits.
  209. X */
  210. Xvoid
  211. XPrintSet(sp)
  212. X   set_type * sp ;
  213. X{
  214. X   int        i ;
  215. X   
  216. X   for (i = 0; i < NextFileNum; ++i) {
  217. X      if (FileList[i]->mask_word < sp->set_size) {
  218. X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  219. X            printf("%s\n",FileList[i]->name) ;
  220. X         }
  221. X      }
  222. X   }
  223. X}
  224. X
  225. X/* Free up all space used by current set of sets and reset all
  226. X * set numbers.
  227. X */
  228. Xvoid
  229. XFlushSets()
  230. X{
  231. X   int         i ;
  232. X   
  233. X   for (i = 0; i < NextSetNum; ++i) {
  234. X      free(TheSets[i]->set_desc) ;
  235. X      free(TheSets[i]) ;
  236. X   }
  237. X   NextSetNum = 0 ;
  238. X}
  239. X
  240. X/* InitList - create an empty identifier list.
  241. X */
  242. Xid_list_type *
  243. XInitList()
  244. X{
  245. X   id_list_type *   idlp ;
  246. X   
  247. X   idlp = (id_list_type *)malloc(sizeof(id_list_type)) ;
  248. X   if (idlp == NULL) {
  249. X      fatal("Out of memory in InitList") ;
  250. X   }
  251. X   idlp->id_count = 0 ;
  252. X   idlp->end_ptr_ptr = & (idlp->id_list) ;
  253. X   idlp->id_list = NULL ;
  254. X   return(idlp) ;
  255. X}
  256. X
  257. X/* ExtendList - add one identifier to an ID list.
  258. X */
  259. Xid_list_type *
  260. XExtendList(idlp, idp)
  261. X   id_list_type * idlp ;
  262. X   id_type *      idp ;
  263. X{
  264. X   *(idlp->end_ptr_ptr) = idp ;
  265. X   idlp->end_ptr_ptr = &(idp->next_id) ;
  266. X   return(idlp) ;
  267. X}
  268. X
  269. X/* InitIid - do all initial processing for iid.
  270. X *   1) Determine the size of a unsigned long for bit set stuff.
  271. X *   2) Find out the name of the pager program to use.
  272. X *   3) Create the HelpSet (pointing to the help file).
  273. X *   4) Setup the prompt.
  274. X */
  275. Xvoid
  276. XInitIid()
  277. X{
  278. X   unsigned long      bit_mask = 1 ;   /* find number of bits in long */
  279. X   int                i ;
  280. X   char *             page ;           /* pager program */
  281. X   
  282. X   do {
  283. X      high_bit = bit_mask ;
  284. X      bit_mask <<= 1 ;
  285. X   } while (bit_mask != 0) ;
  286. X   
  287. X   NextMaskBit = high_bit ;
  288. X   
  289. X   page = getenv("PAGER") ;
  290. X   if (page == NULL) {
  291. X      page = PAGER ;
  292. X   }
  293. X   strcpy(Pager, page) ;
  294. X   
  295. X   FlushFiles() ;
  296. X   InstallFile(HELPFILE) ;
  297. X   HelpSet = (set_type *)
  298. X      malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
  299. X   if (HelpSet == NULL) {
  300. X      fatal("No memory for set in InitIid") ;
  301. X   }
  302. X   HelpSet->set_tail = 0 ;
  303. X   HelpSet->set_desc = NULL ;
  304. X   HelpSet->set_size = MaxCurFile + 1 ;
  305. X   for (i = 0; i <= MaxCurFile; ++i) {
  306. X      HelpSet->set_data[i] = TheFiles[i] ;
  307. X   }
  308. X   
  309. X   page = getenv("PS1") ;
  310. X   if (page == NULL) {
  311. X      page = PROMPT ;
  312. X   }
  313. X   strcpy(Prompt, page) ;
  314. X}
  315. X
  316. X/* InstallFile - install a file name in the symtab. Return the
  317. X * symbol table pointer of the file.
  318. X */
  319. Xsymtab_type *
  320. XInstallFile(fp)
  321. X   char *      fp ;
  322. X{
  323. X   char             c ;
  324. X   unsigned long    hash_code ;
  325. X   int              i ;
  326. X   char *           sp ;
  327. X   symtab_type *    symp ;
  328. X   
  329. X   hash_code = 0 ;
  330. X   sp = fp ;
  331. X   while ((c = *sp++) != '\0') {
  332. X      hash_code <<= 1 ;
  333. X      hash_code ^= (unsigned long)(c) ;
  334. X      if (hash_code & high_bit) {
  335. X         hash_code &= ~ high_bit ;
  336. X         hash_code ^= 1 ;
  337. X      }
  338. X   }
  339. X   hash_code %= HASH_SIZE ;
  340. X   symp = HashTable[hash_code] ;
  341. X   while (symp != NULL && strcmp(symp->name, fp)) {
  342. X      symp = symp->hash_link ;
  343. X   }
  344. X   if (symp == NULL) {
  345. X      symp = (symtab_type *)malloc(sizeof(symtab_type) + strlen(fp)) ;
  346. X      if (symp == NULL) {
  347. X         fatal("No memory for symbol table entry in InstallFile") ;
  348. X      }
  349. X      strcpy(symp->name, fp) ;
  350. X      symp->hash_link = HashTable[hash_code] ;
  351. X      HashTable[hash_code] = symp ;
  352. X      if (NextMaskWord >= FileSpace) {
  353. X         FileSpace += 1000 ;
  354. X         if (TheFiles != NULL) {
  355. X            TheFiles = (unsigned long *)
  356. X               realloc(TheFiles, sizeof(unsigned long) * FileSpace) ;
  357. X         } else {
  358. X            TheFiles = (unsigned long *)
  359. X               malloc(sizeof(unsigned long) * FileSpace) ;
  360. X         }
  361. X         if (TheFiles == NULL) {
  362. X            fatal("No memory for TheFiles in InstallFile") ;
  363. X         }
  364. X         for (i = NextMaskWord; i < FileSpace; ++i) {
  365. X            TheFiles[i] = 0 ;
  366. X         }
  367. X      }
  368. X      symp->mask_word = NextMaskWord ;
  369. X      symp->mask_bit = NextMaskBit ;
  370. X      NextMaskBit >>= 1 ;
  371. X      if (NextMaskBit == 0) {
  372. X         NextMaskBit = high_bit ;
  373. X         ++NextMaskWord ;
  374. X      }
  375. X      if (NextFileNum >= ListSpace) {
  376. X         ListSpace += 1000 ;
  377. X         if (FileList == NULL) {
  378. X            FileList = (symtab_type **)
  379. X               malloc(sizeof(symtab_type *) * ListSpace) ;
  380. X         } else {
  381. X            FileList = (symtab_type **)
  382. X               realloc(FileList, ListSpace * sizeof(symtab_type *)) ;
  383. X         }
  384. X         if (FileList == NULL) {
  385. X            fatal("No memory for FileList in InstallFile") ;
  386. X         }
  387. X      }
  388. X      FileList[NextFileNum++] = symp ;
  389. X      /* put code here to sort the file list by name someday */
  390. X   }
  391. X   TheFiles[symp->mask_word] |= symp->mask_bit ;
  392. X   if (symp->mask_word > MaxCurFile) {
  393. X      MaxCurFile = symp->mask_word ;
  394. X   }
  395. X   return(symp) ;
  396. X}
  397. X
  398. X/* RunPager - run the users pager program on the list of files
  399. X * in the set.
  400. X */
  401. Xvoid
  402. XRunPager(pp, sp)
  403. X   char *     pp ;
  404. X   set_type * sp ;
  405. X{
  406. X   char *         cmd ;
  407. X   int            i ;
  408. X   id_type *      idep ;
  409. X   
  410. X   cmd = (char *)TEMP_ALLOC(SetListSize(sp) + strlen(pp) + 2);
  411. X   strcpy(cmd, pp) ;
  412. X   for (i = 0; i < NextFileNum; ++i) {
  413. X      if (FileList[i]->mask_word < sp->set_size) {
  414. X         if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
  415. X            strcat(cmd, " ") ;
  416. X            strcat(cmd, FileList[i]->name) ;
  417. X         }
  418. X      }
  419. X   }
  420. X   system(cmd) ;
  421. X   TEMP_FREE(cmd) ;
  422. X}
  423. X
  424. X/* AddSet - add a new set to the universal list of sets. Assign
  425. X * it the next set number.
  426. X */
  427. Xvoid
  428. XAddSet(sp)
  429. X   set_type *   sp ;
  430. X{
  431. X   if (NextSetNum >= SetSpace) {
  432. X      SetSpace += 1000 ;
  433. X      if (TheSets != NULL) {
  434. X         TheSets = (set_type **)
  435. X            realloc(TheSets, sizeof(set_type *) * SetSpace) ;
  436. X      } else {
  437. X         TheSets = (set_type **)
  438. X            malloc(sizeof(set_type *) * SetSpace) ;
  439. X      }
  440. X      if (TheSets == NULL) {
  441. X         fatal("No memory for TheSets in AddSet") ;
  442. X      }
  443. X   }
  444. X   sp->set_num = NextSetNum ;
  445. X   TheSets[NextSetNum++] = sp ;
  446. X}
  447. X
  448. X/* RunProg - run a program with arguments from id_list and
  449. X * accept list of file names back from the program which
  450. X * are installed in the symbol table and used to construct
  451. X * a new set.
  452. X */
  453. Xset_type *
  454. XRunProg(pp, idlp)
  455. X   char *         pp ;
  456. X   id_list_type * idlp ;
  457. X{
  458. X   int            c ;
  459. X   char *         cmd ;
  460. X   char *         dp ;
  461. X   char           file [ MAXCMD ] ;
  462. X   int            i ;
  463. X   id_type *      idep ;
  464. X   id_type *      next_id ;
  465. X   FILE *         prog ;
  466. X   set_type *     sp ;
  467. X   
  468. X   cmd = (char *)TEMP_ALLOC(ArgListSize(idlp) + strlen(pp) + 2);
  469. X   FlushFiles() ;
  470. X   strcpy(cmd, pp) ;
  471. X   idep = idlp->id_list ;
  472. X   while (idep != NULL) {
  473. X      strcat(cmd, " ") ;
  474. X      strcat(cmd, idep->id) ;
  475. X      next_id = idep->next_id ;
  476. X      free(idep) ;
  477. X      idep = next_id ;
  478. X   }
  479. X   free(idlp) ;
  480. X   
  481. X   /* run program with popen, reading the output. Assume each
  482. X    * white space terminated string is a file name.
  483. X    */
  484. X   prog = popen(cmd, "r") ;
  485. X   dp = file ;
  486. X   while ((c = getc(prog)) != EOF) {
  487. X      if (isspace(c)) {
  488. X         if (dp != file) {
  489. X            *dp++ = '\0' ;
  490. X            InstallFile(file) ;
  491. X            dp = file ;
  492. X         }
  493. X      } else {
  494. X         *dp++ = c ;
  495. X      }
  496. X   }
  497. X   if (dp != file) {
  498. X      *dp++ = '\0' ;
  499. X      InstallFile(file) ;
  500. X   }
  501. X   if (pclose(prog) != 0) {
  502. X      /* if there was an error make an empty set, who knows what
  503. X       * garbage the program printed.
  504. X       */
  505. X      FlushFiles() ;
  506. X   }
  507. X   
  508. X   sp = (set_type *)
  509. X      malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
  510. X   if (sp == NULL) {
  511. X      fatal("No memory for set in RunProg") ;
  512. X   }
  513. X   sp->set_tail = 0 ;
  514. X   sp->set_desc = (char *)malloc(strlen(cmd) + 1) ;
  515. X   if (sp->set_desc == NULL) {
  516. X      fatal("No memory for set description in RunProg") ;
  517. X   }
  518. X   strcpy(sp->set_desc, cmd) ;
  519. X   sp->set_size = MaxCurFile + 1 ;
  520. X   for (i = 0; i <= MaxCurFile; ++i) {
  521. X      sp->set_data[i] = TheFiles[i] ;
  522. X   }
  523. X   AddSet(sp) ;
  524. X   TEMP_FREE(cmd);
  525. X   return(sp) ;
  526. X}
  527. X
  528. X/* SetDirectory - change the working directory. This will
  529. X * determine which ID file is found by the subprograms.
  530. X */
  531. Xvoid
  532. XSetDirectory(dir)
  533. X   id_type *      dir ;
  534. X{
  535. X   if (chdir(dir->id) != 0) {
  536. X      fprintf(stderr,"Directory %s not accessible.\n",dir) ;
  537. X   }
  538. X   free(dir) ;
  539. X}
  540. X
  541. X/* SetIntersect - construct a new set from the intersection
  542. X * of two others. Also construct a new description string.
  543. X */
  544. Xset_type *
  545. XSetIntersect(sp1, sp2)
  546. X   set_type * sp1 ;
  547. X   set_type * sp2 ;
  548. X{
  549. X   char *     desc ;
  550. X   int        i ;
  551. X   int        len1 ;
  552. X   int        len2 ;
  553. X   set_type * new_set ;
  554. X   int        new_size ;
  555. X   
  556. X   if (sp1->set_tail || sp2->set_tail) {
  557. X      new_size = MAX(sp1->set_size, sp2->set_size) ;
  558. X   } else {
  559. X      new_size = MIN(sp1->set_size, sp2->set_size) ;
  560. X   }
  561. X   new_set = (set_type *)malloc(sizeof(set_type) +
  562. X                                (new_size - 1) * sizeof(unsigned long)) ;
  563. X   if (new_set == NULL) {
  564. X      fatal("No memory for set in SetIntersect") ;
  565. X   }
  566. X   len1 = strlen(sp1->set_desc) ;
  567. X   len2 = strlen(sp2->set_desc) ;
  568. X   desc = (char *)malloc(len1 + len2 + 10) ;
  569. X   if (desc == NULL) {
  570. X      fatal("No memory for set description in SetIntersect") ;
  571. X   }
  572. X   new_set->set_desc = desc ;
  573. X   strcpy(desc,"(") ;
  574. X   ++desc ;
  575. X   strcpy(desc, sp1->set_desc) ;
  576. X   desc += len1 ;
  577. X   strcpy(desc, ") AND (") ;
  578. X   desc += 7 ;
  579. X   strcpy(desc, sp2->set_desc) ;
  580. X   desc += len2 ;
  581. X   strcpy(desc, ")") ;
  582. X   AddSet(new_set) ;
  583. X   new_set->set_size = new_size ;
  584. X   for (i = 0; i < new_size; ++i) {
  585. X      new_set->set_data[i] = 
  586. X         ((i < sp1->set_size) ? sp1->set_data[i] : sp1->set_tail) & 
  587. X         ((i < sp2->set_size) ? sp2->set_data[i] : sp2->set_tail) ;
  588. X   }
  589. X   new_set->set_tail = sp1->set_tail & sp2->set_tail ;
  590. X   return(new_set) ;
  591. X}
  592. X
  593. X/* SetUnion - construct a new set from the union of two others.
  594. X * Also construct a new description string.
  595. X */
  596. Xset_type *
  597. XSetUnion(sp1, sp2)
  598. X   set_type * sp1 ;
  599. X   set_type * sp2 ;
  600. X{
  601. X   char *     desc ;
  602. X   int        i ;
  603. X   int        len1 ;
  604. X   int        len2 ;
  605. X   set_type * new_set ;
  606. X   int        new_size ;
  607. X   
  608. X   new_size = MAX(sp1->set_size, sp2->set_size) ;
  609. X   new_set = (set_type *)malloc(sizeof(set_type) +
  610. X                                (new_size - 1) * sizeof(unsigned long)) ;
  611. X   if (new_set == NULL) {
  612. X      fatal("No memory for set in SetUnion") ;
  613. X   }
  614. X   len1 = strlen(sp1->set_desc) ;
  615. X   len2 = strlen(sp2->set_desc) ;
  616. X   desc = (char *)malloc(len1 + len2 + 9) ;
  617. X   if (desc == NULL) {
  618. X      fatal("No memory for set description in SetUnion") ;
  619. X   }
  620. X   new_set->set_desc = desc ;
  621. X   strcpy(desc,"(") ;
  622. X   ++desc ;
  623. X   strcpy(desc, sp1->set_desc) ;
  624. X   desc += len1 ;
  625. X   strcpy(desc, ") OR (") ;
  626. X   desc += 6 ;
  627. X   strcpy(desc, sp2->set_desc) ;
  628. X   desc += len2 ;
  629. X   strcpy(desc, ")") ;
  630. X   AddSet(new_set) ;
  631. X   new_set->set_size = new_size ;
  632. X   for (i = 0; i < new_size; ++i) {
  633. X      new_set->set_data[i] =
  634. X         ((i < sp1->set_size) ? (sp1->set_data[i]) : sp1->set_tail) |
  635. X         ((i < sp2->set_size) ? (sp2->set_data[i]) : sp2->set_tail) ;
  636. X   }
  637. X   new_set->set_tail = sp1->set_tail | sp2->set_tail ;
  638. X   return(new_set) ;
  639. X}
  640. X
  641. X/* SetInverse - construct a new set from the inverse of another.
  642. X * Also construct a new description string.
  643. X *
  644. X * This is kind of tricky. An inverse set in iid may grow during
  645. X * the course of a session. By NOTing the set_tail extension the
  646. X * inverse at any given time will be defined as the inverse against
  647. X * a universe that grows as additional queries are made and new files
  648. X * are added to the database.
  649. X *
  650. X * Several alternative definitions were possible (snapshot the
  651. X * universe at the time of the NOT, go read the ID file to
  652. X * determine the complete universe), but this one was the one
  653. X * I picked.
  654. X */
  655. Xset_type *
  656. XSetInverse(sp)
  657. X   set_type * sp ;
  658. X{
  659. X   char *     desc ;
  660. X   int        i ;
  661. X   set_type * new_set ;
  662. X   
  663. X   new_set = (set_type *)malloc(sizeof(set_type) +
  664. X                                (sp->set_size - 1) * sizeof(unsigned long)) ;
  665. X   if (new_set == NULL) {
  666. X      fatal("No memory for set in SetInverse") ;
  667. X   }
  668. X   desc = (char *)malloc(strlen(sp->set_desc) + 5) ;
  669. X   if (desc == NULL) {
  670. X      fatal("No memory for set description in SetInverse") ;
  671. X   }
  672. X   new_set->set_desc = desc ;
  673. X   strcpy(desc,"NOT ") ;
  674. X   desc += 4 ;
  675. X   strcpy(desc, sp->set_desc) ;
  676. X   AddSet(new_set) ;
  677. X   new_set->set_size = sp->set_size ;
  678. X   for (i = 0; i < sp->set_size; ++i) {
  679. X      new_set->set_data[i] = ~ sp->set_data[i] ;
  680. X   }
  681. X   new_set->set_tail = ~ sp->set_tail ;
  682. X   return(new_set) ;
  683. X}
  684. X
  685. X/* RunShell - run a program with arguments from id_list.
  686. X */
  687. Xvoid
  688. XRunShell(pp, idlp)
  689. X   char *         pp ;
  690. X   id_list_type * idlp ;
  691. X{
  692. X   char *         cmd ;
  693. X   id_type *      idep ;
  694. X   id_type *      next_id ;
  695. X   
  696. X   cmd = (char *)TEMP_ALLOC(ArgListSize(idlp) + strlen(pp) + 2);
  697. X   strcpy(cmd, pp) ;
  698. X   idep = idlp->id_list ;
  699. X   while (idep != NULL) {
  700. X      strcat(cmd, " ") ;
  701. X      strcat(cmd, idep->id) ;
  702. X      next_id = idep->next_id ;
  703. X      free(idep) ;
  704. X      idep = next_id ;
  705. X   }
  706. X   free(idlp) ;
  707. X   system(cmd) ;
  708. X   TEMP_FREE(cmd);
  709. X}
  710. END_OF_FILE
  711. if test 17113 -ne `wc -c <'iidfun.c'`; then
  712.     echo shar: \"'iidfun.c'\" unpacked with wrong size!
  713. fi
  714. # end of 'iidfun.c'
  715. fi
  716. if test -f 'mkid.c' -a "${1}" != "-c" ; then 
  717.   echo shar: Will not clobber existing file \"'mkid.c'\"
  718. else
  719. echo shar: Extracting \"'mkid.c'\" \(18633 characters\)
  720. sed "s/^X//" >'mkid.c' <<'END_OF_FILE'
  721. Xstatic char copyright[] = "@(#)Copyright (c) 1986, Greg McGary";
  722. Xstatic char sccsid[] = "@(#)mkid.c    1.4 86/11/06";
  723. X
  724. X#include    <bool.h>
  725. X#include    <sys/types.h>
  726. X#include    <sys/stat.h>
  727. X#include    <stdio.h>
  728. X#include    <string.h>
  729. X#include    <ctype.h>
  730. X#include    <id.h>
  731. X#include    <bitops.h>
  732. X#include    <errno.h>
  733. X#include    <extern.h>
  734. X#include        "patchlevel.h"
  735. X
  736. Xint idnHashCmp();
  737. Xint idnQsortCmp();
  738. Xint round2();
  739. Xstruct idname *newIdName();
  740. Xvoid extractId();
  741. Xvoid fileIdArgs();
  742. Xvoid initHashTable();
  743. Xvoid oldIdArgs();
  744. Xvoid rehash();
  745. Xvoid updateID();
  746. Xvoid writeID();
  747. X
  748. Xlong    NameCount;        /* Count of names in database */
  749. Xlong    NumberCount;        /* Count of numbers in database */
  750. Xlong    StringCount;        /* Count of strings in database */
  751. Xlong    SoloCount;        /* Count of identifiers that occur only once */
  752. X
  753. Xlong    HashSize;        /* Total Slots in hash table */
  754. Xlong    HashMaxLoad;        /* Maximum loading of hash table */
  755. Xlong    HashFill;        /* Number of keys inserted in table */
  756. Xlong    HashProbes;        /* Total number of probes */
  757. Xlong    HashSearches;        /* Total number of searches */
  758. Xstruct idname    **HashTable;    /* Vector of idname pointers */
  759. X
  760. Xbool    Verbose = FALSE;
  761. X
  762. Xint    ArgsCount = 0;        /* Count of args to save */
  763. Xint    ScanCount = 0;        /* Count of files to scan */
  764. Xint    PathCount = 0;        /* Count of files covered in database */
  765. Xint    BitArraySize;        /* Size of bit array slice (per name) */
  766. X
  767. Xchar    PWDname[BUFSIZ];    /* The current working directory */
  768. Xchar    absID[BUFSIZ];        /* The absolute name of the database */
  769. X
  770. X
  771. Xchar    *MyName;
  772. Xstatic void
  773. Xusage()
  774. X{
  775. X    fprintf(stderr, "Usage: %s [-f<idfile>] [-s<dir>] [-r<dir>] [(+|-)l[<lang>]] [-v] [(+|-)S<scanarg>] [-a<argfile>] [-] [-u] [files...]\n", MyName);
  776. X    exit(1);
  777. X}
  778. Xmain(argc, argv)
  779. X    int        argc;
  780. X    char        **argv;
  781. X{
  782. X    char        *arg;
  783. X    int        op;
  784. X    FILE        *argFILE = NULL;
  785. X    char        *idFile = IDFILE;
  786. X    char        *rcsDir = NULL;
  787. X    char        *sccsDir = NULL;
  788. X    struct idarg    *idArgs, *idArgHead;
  789. X    bool        keepLang = FALSE;
  790. X    int        argsFrom = 0;
  791. X#define    AF_CMDLINE    0x1    /* file args came on command line */
  792. X#define    AF_FILE        0x2    /* file args came from a file (-f<file>) */
  793. X#define    AF_IDFILE    0x4    /* file args came from an old ID file (-u) */
  794. X#define    AF_QUERY    0x8    /* no file args necessary: usage query */
  795. X
  796. X    MyName = basename(GETARG(argc, argv));
  797. X    if (kshgetwd(PWDname) == NULL) {
  798. X        fprintf(stderr,"%s: cannot get current working directory name.\n",MyName);
  799. X        exit(1);
  800. X    }
  801. X    strcat(PWDname, "/");
  802. X#ifdef ERRLINEBUF
  803. X    setlinebuf(stderr);
  804. X#endif
  805. X
  806. X    idArgs = idArgHead = NEW(struct idarg);
  807. X
  808. X    /*
  809. X        Process some arguments, and snarf-up some
  810. X        others for processing later.
  811. X    */
  812. X    while (argc) {
  813. X        arg = GETARG(argc, argv);
  814. X        if (*arg != '-' && *arg != '+') {
  815. X            argsFrom |= AF_CMDLINE;
  816. X            idArgs->ida_arg = arg;
  817. X            idArgs->ida_flags = IDA_SCAN|IDA_PATH;
  818. X            idArgs->ida_index = postIncr(&PathCount);
  819. X            ScanCount++;
  820. X            idArgs = (idArgs->ida_next = NEW(struct idarg));
  821. X            continue;
  822. X        }
  823. X        op = *arg++;
  824. X        switch (*arg++)
  825. X        {
  826. X        case 'u':
  827. X            argsFrom |= AF_IDFILE;
  828. X            oldIdArgs(idFile, &idArgs);
  829. X            break;
  830. X        case '\0':
  831. X            argsFrom |= AF_FILE;
  832. X            fileIdArgs(stdin, &idArgs);
  833. X            break;
  834. X        case 'a':
  835. X            if ((argFILE = fopen(arg, "r")) == NULL) {
  836. X                filerr("open", arg);
  837. X                exit(1);
  838. X            }
  839. X            argsFrom |= AF_FILE;
  840. X            fileIdArgs(argFILE, &idArgs);
  841. X            break;
  842. X        case 'f':
  843. X            idFile = arg;
  844. X            break;
  845. X        case 'v':
  846. X            Verbose = TRUE;
  847. X            break;
  848. X        case 'S':
  849. X            if (strchr(&arg[-2], '?')) {
  850. X                setScanArgs(op, arg);
  851. X                argsFrom |= AF_QUERY;
  852. X            }
  853. X            /*FALLTHROUGH*/
  854. X        case 'l':
  855. X        case 's':
  856. X        case 'r':
  857. X            idArgs->ida_arg = &arg[-2];
  858. X            idArgs->ida_index = -1;
  859. X            idArgs->ida_flags = IDA_ARG;
  860. X            idArgs = (idArgs->ida_next = NEW(struct idarg));
  861. X            ArgsCount++;
  862. X            break;
  863. X        default:
  864. X            usage();
  865. X        }
  866. X    }
  867. X
  868. X    if (argsFrom & AF_QUERY)
  869. X        exit(0);
  870. X    /*
  871. X        File args should only come from one place.  Ding the
  872. X        user if arguments came from multiple places, or if none
  873. X        were supplied at all.
  874. X    */
  875. X    switch (argsFrom)
  876. X    {
  877. X    case AF_CMDLINE:
  878. X    case AF_FILE:
  879. X    case AF_IDFILE:
  880. X        if (PathCount > 0)
  881. X            break;
  882. X        /*FALLTHROUGH*/
  883. X    case 0:
  884. X        fprintf(stderr, "%s: Use -u, -f<file>, or cmd-line for file args!\n", MyName);
  885. X        usage();
  886. X    default:
  887. X        fprintf(stderr, "%s: Use only one of: -u, -f<file>, or cmd-line for file args!\n", MyName);
  888. X        usage();
  889. X    }
  890. X
  891. X    if (ScanCount == 0)
  892. X        exit(0);
  893. X
  894. X    BitArraySize = (PathCount + 7) >> 3;
  895. X    initHashTable(ScanCount);
  896. X
  897. X    strcpy(absID, spanPath(PWDname, idFile));
  898. X    if (access(idFile, 06) < 0
  899. X    && (errno != ENOENT || access(dirname(idFile), 06) < 0)) {
  900. X        filerr("modify", idFile);
  901. X        exit(1);
  902. X    }
  903. X
  904. X    for (idArgs = idArgHead; idArgs->ida_next; idArgs = idArgs->ida_next) {
  905. X        char        *(*scanner)();
  906. X        FILE        *srcFILE;
  907. X        char        *arg, *lang, *suff, *filter;
  908. X
  909. X        lang = NULL;
  910. X        arg = idArgs->ida_arg;
  911. X        if (idArgs->ida_flags & IDA_ARG) {
  912. X            op = *arg++;
  913. X            switch (*arg++)
  914. X            {
  915. X            case 'l':
  916. X                if (*arg == '\0') {
  917. X                    keepLang = FALSE;
  918. X                    lang = NULL;
  919. X                    break;
  920. X                }
  921. X                if (op == '+')
  922. X                    keepLang = TRUE;
  923. X                lang = arg;
  924. X                break;
  925. X            case 's':
  926. X                sccsDir = arg;
  927. X                break;
  928. X            case 'r':
  929. X                rcsDir = arg;
  930. X                break;
  931. X            case 'S':
  932. X                setScanArgs(op, strsav(arg));
  933. X                break;
  934. X            default:
  935. X                usage();
  936. X            }
  937. X            continue;
  938. X        }
  939. X        if (!(idArgs->ida_flags & IDA_SCAN))
  940. X            goto skip;
  941. X        if (lang == NULL) {
  942. X            if ((suff = strrchr(arg, '.')) == NULL)
  943. X                suff = "";
  944. X            if (((lang = getLanguage(suff)) == NULL) &&
  945. X                ((lang = getLanguage(".default")) == NULL)) {
  946. X                fprintf(stderr, "%s: No language assigned to suffix: `%s'\n", MyName, suff);
  947. X                goto skip;
  948. X            }
  949. X        }
  950. X        if ((scanner = getScanner(lang)) == NULL) {
  951. X            fprintf(stderr, "%s: No scanner for language: `%s'\n", MyName, lang);
  952. X            goto skip;
  953. X        }
  954. X        filter = getFilter(suff);
  955. X        if ((srcFILE = openSrcFILE(arg, sccsDir, rcsDir, filter)) == NULL)
  956. X            goto skip;
  957. X        if (Verbose)
  958. X            if (filter) {
  959. X                fprintf(stderr, "%s: ",lang);
  960. X                fprintf(stderr, filter, arg);
  961. X                fprintf(stderr, "\n");
  962. X            } else {
  963. X                fprintf(stderr, "%s: %s\n", lang, arg);
  964. X            }
  965. X        extractId(scanner, srcFILE, idArgs->ida_index);
  966. X        closeSrcFILE(srcFILE, filter);
  967. X    skip:
  968. X        if (!keepLang)
  969. X            lang = NULL;
  970. X    }
  971. X
  972. X    if (HashFill == 0)
  973. X        exit(0);
  974. X
  975. X    if (Verbose) {
  976. X        fprintf(stderr, "mkid patchlevel %d:\n", PATCHLEVEL);
  977. X        fprintf(stderr, "Compressing Hash Table...\n");
  978. X    }
  979. X    hashCompress(HashTable, HashSize);
  980. X    if (Verbose)
  981. X        fprintf(stderr, "Sorting Hash Table...\n");
  982. X    qsort(HashTable, HashFill, sizeof(struct idname *), idnQsortCmp);
  983. X
  984. X    if (argsFrom == AF_IDFILE) {
  985. X        if (Verbose)
  986. X            fprintf(stderr, "Merging Tables...\n");
  987. X        updateID(idFile, idArgHead);
  988. X    }
  989. X
  990. X    if (Verbose)
  991. X        fprintf(stderr, "Writing `%s'...\n", idFile);
  992. X    writeID(idFile, idArgHead);
  993. X
  994. X    if (Verbose) {
  995. X        float loadFactor = (float)HashFill / (float)HashSize;
  996. X        float aveProbes = (float)HashProbes / (float)HashSearches;
  997. X        float aveOccur = (float)HashSearches / (float)HashFill;
  998. X        fprintf(stderr, "Names: %ld, ", NameCount);
  999. X        fprintf(stderr, "Numbers: %ld, ", NumberCount);
  1000. X        fprintf(stderr, "Strings: %ld, ", StringCount);
  1001. X        fprintf(stderr, "Solo: %ld, ", SoloCount);
  1002. X        fprintf(stderr, "Total: %ld\n", HashFill);
  1003. X        fprintf(stderr, "Occurances: %.2f, ", aveOccur);
  1004. X        fprintf(stderr, "Load: %.2f, ", loadFactor);
  1005. X        fprintf(stderr, "Probes: %.2f\n", aveProbes);
  1006. X    }
  1007. X    exit(0);
  1008. X}
  1009. X
  1010. Xvoid
  1011. XextractId(getId, srcFILE, index)
  1012. X    register char    *(*getId)();
  1013. X    register FILE    *srcFILE;
  1014. X    int        index;
  1015. X{
  1016. X    register struct idname    **slot;
  1017. X    register char    *key;
  1018. X    int        flags;
  1019. X
  1020. X    while ((key = (*getId)(srcFILE, &flags)) != NULL) {
  1021. X        slot = (struct idname **)hashSearch(key, HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
  1022. X        HashSearches++;
  1023. X        if (*slot != NULL) {
  1024. X            (*slot)->idn_flags |= flags;
  1025. X            BITSET((*slot)->idn_bitv, index);
  1026. X            continue;
  1027. X        }
  1028. X        *slot = newIdName(key);
  1029. X        (*slot)->idn_flags = IDN_SOLO|flags;
  1030. X        BITSET((*slot)->idn_bitv, index);
  1031. X        if (HashFill++ >= HashMaxLoad)
  1032. X            rehash();
  1033. X    }
  1034. X}
  1035. X
  1036. X/* As the database is written, may need to adjust the file names.
  1037. X * If we are generating the ID file in a remote directory, then
  1038. X * adjust the file names to be relative to the location of the
  1039. X * ID database.
  1040. X *
  1041. X * (This would be a common useage if you want to make a database
  1042. X * for a directory which you have no write access to, so you cannot
  1043. X * create the ID file.)
  1044. X */
  1045. Xvoid
  1046. XwriteID(idFile, idArgs)
  1047. X    char        *idFile;
  1048. X    struct idarg    *idArgs;
  1049. X{
  1050. X    register struct idname    **idnp;
  1051. X    register struct idname    *idn;
  1052. X    register int    i;
  1053. X    char        *vecBuf;
  1054. X    FILE        *idFILE;
  1055. X    int        count;
  1056. X    int        lasti;
  1057. X    long        before, after;
  1058. X    int        length, longest;
  1059. X    struct idhead    idh;
  1060. X    int        fixnames;
  1061. X    char *        lsl;
  1062. X
  1063. X    if ((lsl = strrchr(relPath(PWDname, absID),'/')) == NULL) {
  1064. X        /* The database is in the cwd, don't adjust the names */
  1065. X        fixnames = FALSE;
  1066. X    } else {
  1067. X        /* The database is not in cwd, adjust names so they are
  1068. X         * relative to the location of the database, make absID
  1069. X         * just be the directory path to ID.
  1070. X         */
  1071. X        fixnames = TRUE;
  1072. X        *(lsl+1) = '\0';
  1073. X    }
  1074. X    if ((idFILE = fopen(idFile, "w+")) == NULL) {
  1075. X        filerr("create", idFile);
  1076. X        exit(1);
  1077. X    }
  1078. X    fseek(idFILE, (long)sizeof(struct idhead), 0);
  1079. X
  1080. X    /* write out the list of pathnames */
  1081. X    idh.idh_argo = ftell(idFILE);
  1082. X    for (i = lasti = 0; idArgs->ida_next; idArgs = idArgs->ida_next) {
  1083. X        if (idArgs->ida_index > 0)
  1084. X            while (++lasti < idArgs->ida_index)
  1085. X                i++, putc('\0', idFILE);
  1086. X        if (fixnames) {
  1087. X            fputs(relPath(absID,spanPath(PWDname,idArgs->ida_arg)), idFILE);
  1088. X        } else {
  1089. X            fputs(idArgs->ida_arg, idFILE);
  1090. X        }
  1091. X        i++, putc('\0', idFILE);
  1092. X    }
  1093. X    idh.idh_argc = i;
  1094. X    idh.idh_pthc = PathCount;
  1095. X
  1096. X    /* write out the list of identifiers */
  1097. X    i = 1;
  1098. X    if (idh.idh_pthc >= 0x000000ff)
  1099. X        i++;
  1100. X    if (idh.idh_pthc >= 0x0000ffff)
  1101. X        i++;
  1102. X    if (idh.idh_pthc >= 0x00ffffff)
  1103. X        i++;
  1104. X    idh.idh_vecc = i;
  1105. X
  1106. X    vecBuf = malloc((idh.idh_pthc + 1) * idh.idh_vecc);
  1107. X
  1108. X    putc('\377', idFILE);
  1109. X    before = idh.idh_namo = ftell(idFILE);
  1110. X    longest = 0;
  1111. X    for (idnp = HashTable, i = 0; i < HashFill; i++, idnp++) {
  1112. X        idn = *idnp;
  1113. X        if ((idn == NULL) || (idn->idn_name[0] == '\0')) {
  1114. X            HashFill--; i--;
  1115. X            continue;
  1116. X        }
  1117. X        if (idn->idn_flags & IDN_SOLO)
  1118. X            SoloCount++;
  1119. X        if (idn->idn_flags & IDN_NUMBER)
  1120. X            NumberCount++;
  1121. X        if (idn->idn_flags & IDN_NAME)
  1122. X            NameCount++;
  1123. X        if (idn->idn_flags & IDN_STRING)
  1124. X            StringCount++;
  1125. X
  1126. X        putc((*idnp)->idn_flags, idFILE);
  1127. X        fputs(idn->idn_name, idFILE);
  1128. X        putc('\0', idFILE);
  1129. X
  1130. X        count = bitsToVec(vecBuf, (*idnp)->idn_bitv, idh.idh_pthc, idh.idh_vecc);
  1131. X        fwrite(vecBuf, idh.idh_vecc, count, idFILE);
  1132. X        putc('\377', idFILE);
  1133. X        after = ftell(idFILE);
  1134. X        
  1135. X        if ((length = (after - before)) > longest)
  1136. X            longest = length;
  1137. X        before = after;
  1138. X    }
  1139. X    idh.idh_namc = i;
  1140. X    putc('\377', idFILE);
  1141. X    idh.idh_endo = ftell(idFILE);
  1142. X    idh.idh_bsiz = longest;
  1143. X
  1144. X    /* write out the header */
  1145. X    strncpy(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic));
  1146. X    idh.idh_vers = IDH_VERS;
  1147. X    fseek(idFILE, 0L, 0);
  1148. X    fwrite(&idh, sizeof(struct idhead), 1, idFILE);
  1149. X
  1150. X    fclose(idFILE);
  1151. X}
  1152. X
  1153. X/*
  1154. X    Build an idarg vector from pathnames contained in an existing
  1155. X    id file.  Only include pathnames for files whose modification
  1156. X    time is later than that of the id file itself.
  1157. X*/
  1158. Xvoid
  1159. XoldIdArgs(idFile, idArgsP)
  1160. X    char        *idFile;
  1161. X    struct idarg    **idArgsP;
  1162. X{
  1163. X    struct stat    statBuf;
  1164. X    struct idhead    idh;
  1165. X    FILE        *idFILE;
  1166. X    register int    i;
  1167. X    register char    *strings;
  1168. X    time_t        idModTime;
  1169. X
  1170. X    if ((idFILE = fopen(idFile, "r")) == NULL) {
  1171. X        filerr("open", idFile);
  1172. X        usage();
  1173. X    }
  1174. X    /*
  1175. X    *  Open the id file, get its mod-time, and read its header.
  1176. X    */
  1177. X    if (fstat(fileno(idFILE), &statBuf) < 0) {
  1178. X        filerr("stat", idFile);
  1179. X        usage();
  1180. X    }
  1181. X    idModTime = statBuf.st_mtime;
  1182. X    fread(&idh, sizeof(struct idhead), 1, idFILE);
  1183. X    if (!strnequ(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic))) {
  1184. X        fprintf(stderr, "%s: Not an id file: `%s'\n", MyName, idFile);
  1185. X        exit(1);
  1186. X    }
  1187. X    if (idh.idh_vers != IDH_VERS) {
  1188. X        fprintf(stderr, "%s: ID version mismatch (%ld,%ld)\n", MyName, idh.idh_vers, IDH_VERS);
  1189. X        exit(1);
  1190. X    }
  1191. X
  1192. X    /*
  1193. X    *  Read in the id pathnames, compare their mod-times with
  1194. X    *  the id file, and incorporate the pathnames of recently modified 
  1195. X    *  files in the idarg vector.  Also, construct a mask of
  1196. X    *  bit array positions we want to turn off when we build the
  1197. X    *  initial hash-table.
  1198. X    */
  1199. X    fseek(idFILE, idh.idh_argo, 0);
  1200. X    strings = malloc(i = idh.idh_namo - idh.idh_argo);
  1201. X    fread(strings, i, 1, idFILE);
  1202. X    ScanCount = 0;
  1203. X    for (i = 0; i < idh.idh_argc; i++) {
  1204. X        (*idArgsP)->ida_arg = strings;
  1205. X        if (*strings == '+' || *strings == '-') {
  1206. X            (*idArgsP)->ida_flags = IDA_ARG;
  1207. X            (*idArgsP)->ida_index = -1;
  1208. X        } else {
  1209. X            (*idArgsP)->ida_flags = IDA_PATH;
  1210. X            (*idArgsP)->ida_index = postIncr(&PathCount);
  1211. X            if (stat(strings, &statBuf) < 0) {
  1212. X                filerr("stat", strings);
  1213. X            } else if (statBuf.st_mtime >= idModTime) {
  1214. X                (*idArgsP)->ida_flags |= IDA_SCAN;
  1215. X                ScanCount++;
  1216. X            }
  1217. X        }
  1218. X        (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
  1219. X        while (*strings++)
  1220. X            ;
  1221. X    }
  1222. X    if (ScanCount == 0) {
  1223. X        fclose(idFILE);
  1224. X        exit(0);
  1225. X    }
  1226. X    fclose(idFILE);
  1227. X}
  1228. X
  1229. Xvoid
  1230. XupdateID(idFile, idArgs)
  1231. X    char        *idFile;
  1232. X    struct idarg    *idArgs;
  1233. X{
  1234. X    struct idname    *idn;
  1235. X    struct idhead    idh;
  1236. X    register char    *bitArray;
  1237. X    char        *entry;
  1238. X    register int    i;
  1239. X    FILE        *idFILE;
  1240. X    int        cmp, count, size;
  1241. X    char        *bitsOff;
  1242. X    struct idname    **newTable, **mergeTable;
  1243. X    struct idname    **t1, **t2, **tm;
  1244. X
  1245. X    if ((idFILE = fopen(idFile, "r")) == NULL)
  1246. X        filerr("open", idFile);
  1247. X    fread(&idh, sizeof(struct idhead), 1, idFILE);
  1248. X
  1249. X    entry = malloc(idh.idh_bsiz);
  1250. X
  1251. X    bitsOff = malloc(BitArraySize);
  1252. X    bzero(bitsOff, BitArraySize);
  1253. X    for (i = 0; idArgs->ida_next; idArgs = idArgs->ida_next)
  1254. X        if (idArgs->ida_flags & IDA_SCAN)
  1255. X            BITSET(bitsOff, idArgs->ida_index);
  1256. X
  1257. X    bitArray = malloc(BitArraySize);
  1258. X    bzero(bitArray, BitArraySize);
  1259. X    t2 = newTable = (struct idname **)malloc((idh.idh_namc + 1) * sizeof(struct idname *));
  1260. X    fseek(idFILE, idh.idh_namo, 0);
  1261. X    count = 0;
  1262. X    for (i = 0; i < idh.idh_namc; i++) {
  1263. X        size = 1 + fgets0(entry, idh.idh_bsiz, idFILE);
  1264. X        getsFF(&entry[size], idFILE);
  1265. X        vecToBits(bitArray, &entry[size], idh.idh_vecc);
  1266. X        bitsclr(bitArray, bitsOff, BitArraySize);
  1267. X        if (!bitsany(bitArray, BitArraySize))
  1268. X            continue;
  1269. X        *t2 = newIdName(ID_STRING(entry));
  1270. X        bitsset((*t2)->idn_bitv, bitArray, BitArraySize);
  1271. X        (*t2)->idn_flags = ID_FLAGS(entry);
  1272. X        bzero(bitArray, BitArraySize);
  1273. X        t2++; count++;
  1274. X    }
  1275. X    *t2 = NULL;
  1276. X
  1277. X    t1 = HashTable;
  1278. X    t2 = newTable;
  1279. X    tm = mergeTable = (struct idname **)calloc(HashFill + count + 1, sizeof(struct idname *));
  1280. X    while (*t1 && *t2) {
  1281. X        cmp = strcmp((*t1)->idn_name, (*t2)->idn_name);
  1282. X        if (cmp < 0)
  1283. X            *tm++ = *t1++;
  1284. X        else if (cmp > 0)
  1285. X            *tm++ = *t2++;
  1286. X        else {
  1287. X            (*t1)->idn_flags |= (*t2)->idn_flags;
  1288. X            (*t1)->idn_flags &= ~IDN_SOLO;
  1289. X            bitsset((*t1)->idn_bitv, (*t2)->idn_bitv, BitArraySize);
  1290. X            *tm++ = *t1;
  1291. X            t1++, t2++;
  1292. X        }
  1293. X    }
  1294. X    while (*t1)
  1295. X        *tm++ = *t1++;
  1296. X    while (*t2)
  1297. X        *tm++ = *t2++;
  1298. X    *tm = NULL;
  1299. X    HashTable = mergeTable;
  1300. X    HashFill = tm - mergeTable;
  1301. X}
  1302. X
  1303. X/*
  1304. X    Cons up a list of idArgs as supplied in a file.
  1305. X*/
  1306. Xvoid
  1307. XfileIdArgs(argFILE, idArgsP)
  1308. X    FILE        *argFILE;
  1309. X    struct idarg    **idArgsP;
  1310. X{
  1311. X    int        fileCount;
  1312. X    char        buf[BUFSIZ];
  1313. X    char        *arg;
  1314. X
  1315. X    fileCount = 0;
  1316. X    while (fgets(buf, sizeof(buf), argFILE)) {
  1317. X        (*idArgsP)->ida_arg = arg = strnsav(buf, strlen(buf)-1);
  1318. X        if (*arg == '+' || *arg == '-') {
  1319. X            (*idArgsP)->ida_flags = IDA_ARG;
  1320. X            (*idArgsP)->ida_index = -1;
  1321. X        } else {
  1322. X            (*idArgsP)->ida_flags = IDA_SCAN|IDA_PATH;
  1323. X            (*idArgsP)->ida_index = postIncr(&PathCount);
  1324. X            ScanCount++;
  1325. X        }
  1326. X        (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
  1327. X    }
  1328. X}
  1329. X
  1330. Xvoid
  1331. XinitHashTable(pathCount)
  1332. X    int        pathCount;
  1333. X{
  1334. X    if ((HashSize = round2((pathCount << 6) + 511)) > 0x8000)
  1335. X        HashSize = 0x8000;
  1336. X    HashMaxLoad = HashSize - (HashSize >> 4);    /* about 94% */
  1337. X    HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
  1338. X}
  1339. X
  1340. X/*
  1341. X    Double the size of the hash table in the
  1342. X    event of overflow...
  1343. X*/
  1344. Xvoid
  1345. Xrehash()
  1346. X{
  1347. X    long        oldHashSize = HashSize;
  1348. X    struct idname    **oldHashTable = HashTable;
  1349. X    register struct idname    **htp;
  1350. X    register struct idname    **slot;
  1351. X
  1352. X    HashSize *= 2;
  1353. X    if (Verbose)
  1354. X        fprintf(stderr, "Rehashing... (doubling size to %ld)\n", HashSize);
  1355. X    HashMaxLoad = HashSize - (HashSize >> 4);
  1356. X    HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
  1357. X
  1358. X    HashFill = 0;
  1359. X    for (htp = oldHashTable; htp < &oldHashTable[oldHashSize]; htp++) {
  1360. X        if (*htp == NULL)
  1361. X            continue;
  1362. X        slot = (struct idname **)hashSearch((*htp)->idn_name, (char *)HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
  1363. X        if (*slot) {
  1364. X            fprintf(stderr, "%s: Duplicate hash entry!\n");
  1365. X            exit(1);
  1366. X        }
  1367. X        *slot = *htp;
  1368. X        HashSearches++;
  1369. X        HashFill++;
  1370. X    }
  1371. X    free(oldHashTable);
  1372. X}
  1373. X
  1374. X/*
  1375. X    Round a given number up to the nearest power of 2.
  1376. X*/
  1377. Xint
  1378. Xround2(rough)
  1379. X    int        rough;
  1380. X{
  1381. X    int        round;
  1382. X
  1383. X    round = 1;
  1384. X    while (rough) {
  1385. X        round <<= 1;
  1386. X        rough >>= 1;
  1387. X    }
  1388. X    return round;
  1389. X}
  1390. X
  1391. X/*
  1392. X    `compar' function for hashSearch()
  1393. X*/
  1394. Xint
  1395. XidnHashCmp(key, idn)
  1396. X    char        *key;
  1397. X    struct idname    **idn;
  1398. X{
  1399. X    int        collate;
  1400. X
  1401. X    if (*idn == NULL)
  1402. X        return 0;
  1403. X    
  1404. X    if ((collate = strcmp(key, (*idn)->idn_name)) == 0)
  1405. X        (*idn)->idn_flags &= ~IDN_SOLO;    /* we found another occurance */
  1406. X
  1407. X    return collate;
  1408. X}
  1409. X
  1410. X/*
  1411. X    `compar' function for qsort().
  1412. X*/
  1413. Xint
  1414. XidnQsortCmp(idn1, idn2)
  1415. X    struct idname    **idn1;
  1416. X    struct idname    **idn2;
  1417. X{
  1418. X    if (*idn1 == *idn2)
  1419. X        return 0;
  1420. X    if (*idn1 == NULL)
  1421. X        return 1;
  1422. X    if (*idn2 == NULL)
  1423. X        return -1;
  1424. X
  1425. X    return strcmp((*idn1)->idn_name, (*idn2)->idn_name);
  1426. X}
  1427. X
  1428. X/*
  1429. X    Allocate a new idname struct and fill in the name field.
  1430. X    We allocate memory in large chunks to avoid frequent
  1431. X    calls to malloc() which is a major pig.
  1432. X*/
  1433. Xstruct idname *
  1434. XnewIdName(name)
  1435. X    char        *name;
  1436. X{
  1437. X    register struct idname    *idn;
  1438. X    register char    *allocp;
  1439. X    register int    allocsiz;
  1440. X    static char    *allocBuf = NULL;
  1441. X    static char    *allocEnd = NULL;
  1442. X#define    ALLOCSIZ    (8*1024)
  1443. X
  1444. X    allocsiz = sizeof(struct idname) + strlen(name) + 1 + BitArraySize;
  1445. X    allocsiz += (sizeof(long) - 1);
  1446. X    allocsiz &= ~(sizeof(long) - 1);
  1447. X
  1448. X    allocp = allocBuf;
  1449. X    allocBuf += allocsiz;
  1450. X    if (allocBuf > allocEnd) {
  1451. X        allocBuf = malloc(ALLOCSIZ);
  1452. X        allocEnd = &allocBuf[ALLOCSIZ];
  1453. X        allocp = allocBuf;
  1454. X        allocBuf += allocsiz;
  1455. X    }
  1456. X
  1457. X    idn = (struct idname *)allocp;
  1458. X    allocp += sizeof(struct idname);
  1459. X    idn->idn_bitv = allocp;
  1460. X    for (allocsiz = BitArraySize; allocsiz--; allocp++)
  1461. X        *allocp = '\0';
  1462. X    idn->idn_name = strcpy(allocp, name);
  1463. X
  1464. X    return idn;
  1465. X}
  1466. X
  1467. Xint
  1468. XpostIncr(ip)
  1469. X    int        *ip;
  1470. X{
  1471. X    register int    i;
  1472. X    int        save;
  1473. X
  1474. X    save = *ip;
  1475. X    i = save + 1;
  1476. X    if ((i & 0x00ff) == 0x00ff)
  1477. X        i++;
  1478. X    if ((i & 0xff00) == 0xff00)    /* This isn't bloody likely */
  1479. X        i += 0x100;
  1480. X    *ip = i;
  1481. X
  1482. X    return save;
  1483. X}
  1484. X
  1485. X/*
  1486. X    Move all non-NULL table entries to the front of the table.
  1487. X    return the number of non-NULL elements in the table.
  1488. X*/
  1489. Xint
  1490. XhashCompress(table, size)
  1491. X    char        **table;
  1492. X    int        size;
  1493. X{
  1494. X    register char    **front;
  1495. X    register char    **back;
  1496. X
  1497. X    front = &table[-1];
  1498. X    back = &table[size];
  1499. X
  1500. X    for (;;) {
  1501. X        while (*--back == NULL)
  1502. X            ;
  1503. X        if (back < front)
  1504. X            break;
  1505. X        while (*++front != NULL)
  1506. X            ;
  1507. X        if (back < front)
  1508. X            break;
  1509. X        *front = *back;
  1510. X    }
  1511. X
  1512. X    return (back - table + 1);
  1513. X}
  1514. END_OF_FILE
  1515. if test 18633 -ne `wc -c <'mkid.c'`; then
  1516.     echo shar: \"'mkid.c'\" unpacked with wrong size!
  1517. fi
  1518. # end of 'mkid.c'
  1519. fi
  1520. echo shar: End of archive 5 \(of 7\).
  1521. cp /dev/null ark5isdone
  1522. MISSING=""
  1523. for I in 1 2 3 4 5 6 7 ; do
  1524.     if test ! -f ark${I}isdone ; then
  1525.     MISSING="${MISSING} ${I}"
  1526.     fi
  1527. done
  1528. if test "${MISSING}" = "" ; then
  1529.     echo You have unpacked all 7 archives.
  1530.     rm -f ark[1-9]isdone
  1531. else
  1532.     echo You still need to unpack the following archives:
  1533.     echo "        " ${MISSING}
  1534. fi
  1535. ##  End of shell archive.
  1536. exit 0
  1537.  
  1538. exit 0 # Just in case...
  1539.